package com.ipzoe.web.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayOpenAuthTokenAppModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.ijpay.core.kit.QrCodeKit;
import com.ipzoe.common.core.domain.AjaxResult;
import com.ipzoe.common.utils.sign.Base64;
import com.ipzoe.common.utils.spring.SpringContextHolder;
import com.ipzoe.framework.controller.AbstractAliPayApiController;
import com.ipzoe.mem.domain.Member;
import com.ipzoe.mem.domain.MemberRechargePackage;
import com.ipzoe.mem.service.IMemberRechargePackageService;
import com.ipzoe.oms.domain.Order;
import com.ipzoe.oms.service.IOrderService;
import com.ipzoe.web.core.config.pay.AliPayProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Controller
@RequestMapping("/api/v1/aliPay")
public class AliPayController extends AbstractAliPayApiController {
    private static final Logger log = LoggerFactory.getLogger(AliPayController.class);

    @Autowired
    private AliPayProperties aliPayProperties;
    @Autowired
    private IOrderService iOrderService;
    @Autowired
    private IMemberRechargePackageService iMemberRechargePackageService;

    private String notifyUrl;

    /**
     * 普通公钥模式
     */
     private final static String NOTIFY_URL = "/aliPay/notify_url";
    /**
     * 证书模式
     */
//    private final static String NOTIFY_URL = "/aliPay/cert_notify_url";
//    private final static String RETURN_URL = "/aliPay/return_url";
    /**
     * 证书模式
     */
    private final static String RETURN_URL = "/aliPay/cert_return_url";

    @Override
    public AliPayApiConfig getApiConfig() throws AlipayApiException {
        AliPayApiConfig aliPayApiConfig;
        try {
            aliPayApiConfig = AliPayApiConfigKit.getApiConfig(aliPayProperties.getAppId());
        } catch (Exception e) {
//            String basePath = null;
//            try {
//                basePath = ResourceUtils.getURL("classpath:").getPath();
//                if (basePath.contains("jar!")) {
//                    if (basePath.startsWith("file:")) {
//                        basePath = basePath.replace("file:", "");
//                    }
//                }
//            } catch (FileNotFoundException ex) {
//                ex.printStackTrace();
//            }


            aliPayApiConfig = AliPayApiConfig.builder()
                    .setAppId(aliPayProperties.getAppId())
                    .setAliPayPublicKey(aliPayProperties.getPublicKey())
                    .setAppCertPath(aliPayProperties.getAppCertPath())
                    .setAliPayCertPath(aliPayProperties.getAliPayCertPath())
                    .setAliPayRootCertPath(aliPayProperties.getAliPayRootCertPath())
                    .setCharset("UTF-8")
                    .setPrivateKey(aliPayProperties.getPrivateKey())
                    .setServiceUrl(aliPayProperties.getServerUrl())
                    .setSignType("RSA2")
                    // 普通公钥方式
//                    .build();
                    // 证书模式
                    .buildByCert();
        }
//        notifyUrl = aliPayProperties.getDomain().concat("/api/v1/aliPay/notify_url");
        notifyUrl = aliPayProperties.getDomain().concat("/api/v1/aliPay/cert_notify_url");
        return aliPayApiConfig;
    }

    /**
     * 扫码支付
     */
    @RequestMapping(value = "/tradePreCreatePay")
    @ResponseBody
    public AjaxResult tradePreCreatePay(HttpServletRequest request, HttpServletResponse response,@RequestParam("packageId") Long packageId) throws IOException {

        if (packageId==null) {
            return AjaxResult.error(400,"未选择购买的套餐");
        }

        //获取当前登录的会员
        Member member = (Member) request.getAttribute("member");
        //查询该账户下是否存在待支付的该套餐的订单
//        LambdaQueryWrapper<Order> orderLqw = new LambdaQueryWrapper<>();
//        orderLqw.eq(Order::getMemberId, member.getId())
//                .eq(Order::getPackageId, packageId)
//                .eq(Order::getPayType,2)
//                .eq(Order::getStatus,0);
//        Order order = iOrderService.getOne(orderLqw);
//
//        if(order != null){
//            return AjaxResult.success(order.getPayImgName());
//        }

        String orderNo = iOrderService.generateOrderSn();

        MemberRechargePackage rechargePackage = iMemberRechargePackageService.getById(packageId);
        if(rechargePackage == null){
            return AjaxResult.error(400,"未选择购买的套餐");
        }

        String activeProfile = SpringContextHolder.getApplicationContext().getEnvironment().getActiveProfiles()[0];
        //单位元
        String totalFee = "0.01";
        if ("prod".equals(activeProfile)) {
            totalFee = String.valueOf(rechargePackage.getPrice());
        }else{
            totalFee = "0.01";
        }

        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setSubject("dan潜水-会员充值");
        model.setTotalAmount(totalFee);
        model.setQrCodeTimeoutExpress("2h");
        model.setOutTradeNo(orderNo);
        model.setBody(Order.toPayParam(orderNo
                ,String.valueOf(rechargePackage.getPrice())
                , rechargePackage.getId()
                , member.getId()
                , 2,"ali_pc"));

        log.info("支付宝统一下单req:" + JSON.toJSONString(model));
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            String resultStr = AliPayApi.tradePrecreatePayToResponse(model, notifyUrl).getBody();
            log.info("支付宝统一下单res:" + resultStr);
            JSONObject jsonObject = JSONObject.parseObject(resultStr);
            String qrCodeUrl = jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code");
            String name = "ALIQR_"+orderNo+".png";

            QrCodeKit.encodeOutPutSteam(stream,qrCodeUrl, BarcodeFormat.QR_CODE, 0, ErrorCorrectionLevel.H,"png", 200, 200);
            AjaxResult ajax = AjaxResult.success();
            ajax.put("img", Base64.encode(stream.toByteArray()));
            return ajax;

        } catch (Exception e) {
            log.error("支付宝下单错误",e);
            return AjaxResult.error(400,"支付异常，请稍后再试");
        }finally {
            stream.close();
        }
    }

    @RequestMapping(value = "/notify_url",method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String notifyUrl(HttpServletRequest request) {
        try {
            // 获取支付宝POST过来反馈信息
            Map<String, String> params = AliPayApi.toMap(request);
            log.info("支付宝支付通知=" + JSON.toJSONString(params));

            boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliPayProperties.getPublicKey(), "UTF-8", "RSA2");

            if (verifyResult) {
                String orderNo = params.get("out_trade_no");
                String payParam = params.get("body");
                log.info("支付宝回调body参数："+payParam);
                iOrderService.payReturn(payParam, "TRADE_SUCCESS".equalsIgnoreCase(params.get("trade_status")), JSON.toJSONString(params));
                return "success";
            } else {
                log.error("notify_url 验证失败");
                return "failure";
            }
        } catch (Exception e) {
            log.error("notify_url 验证失败",e);
            return "failure";
        }
    }

    @RequestMapping(value = "/cert_notify_url",method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String certNotifyUrl(HttpServletRequest request) {
        try {
            // 获取支付宝POST过来反馈信息
            Map<String, String> params = AliPayApi.toMap(request);
            log.info("支付宝支付通知=" + JSON.toJSONString(params));

            boolean verifyResult = AlipaySignature.rsaCertCheckV1(params, aliPayProperties.getAliPayCertPath(), "UTF-8", "RSA2");

            if (verifyResult) {
                String orderNo = params.get("out_trade_no");
                String payParam = params.get("body");
                iOrderService.payReturn(payParam, "TRADE_SUCCESS".equalsIgnoreCase(params.get("trade_status")), JSON.toJSONString(params));
                return "success";
            } else {
                log.error("notify_url 验证失败");
                return "failure";
            }
        } catch (AlipayApiException e) {
            log.error("notify_url 验证失败",e);
            return "failure";
        }
    }


    /**
     * 应用授权回调
     */
    @RequestMapping(value = "/redirect_uri")
    @ResponseBody
    public String redirectUri(@RequestParam("app_id") String appId, @RequestParam("app_auth_code") String appAuthCode) {
        try {
            System.out.println("app_id:" + appId);
            System.out.println("app_auth_code:" + appAuthCode);
            //使用app_auth_code换取app_auth_token
            AlipayOpenAuthTokenAppModel model = new AlipayOpenAuthTokenAppModel();
            model.setGrantType("authorization_code");
            model.setCode(appAuthCode);
            return AliPayApi.openAuthTokenAppToResponse(model).getBody();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @RequestMapping(value = "/return_url")
    @ResponseBody
    public String returnUrl(HttpServletRequest request) {
        try {
            // 获取支付宝GET过来反馈信息
            Map<String, String> map = AliPayApi.toMap(request);
            for (Map.Entry<String, String> entry : map.entrySet()) {
                System.out.println(entry.getKey() + " = " + entry.getValue());
            }

            boolean verifyResult = AlipaySignature.rsaCheckV1(map, aliPayProperties.getPublicKey(), "UTF-8",
                    "RSA2");

            if (verifyResult) {
                // TODO 请在这里加上商户的业务逻辑程序代码
                System.out.println("return_url 验证成功");

                return "success";
            } else {
                System.out.println("return_url 验证失败");
                // TODO
                return "failure";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "failure";
        }
    }

    @RequestMapping(value = "/cert_return_url")
    @ResponseBody
    public String certReturnUrl(HttpServletRequest request) {
        try {
            // 获取支付宝GET过来反馈信息
            Map<String, String> map = AliPayApi.toMap(request);
            for (Map.Entry<String, String> entry : map.entrySet()) {
                System.out.println(entry.getKey() + " = " + entry.getValue());
            }

            boolean verifyResult = AlipaySignature.rsaCertCheckV1(map, aliPayProperties.getAliPayCertPath(), "UTF-8",
                    "RSA2");

            if (verifyResult) {
                // TODO 请在这里加上商户的业务逻辑程序代码
                System.out.println("certReturnUrl 验证成功");

                return "success";
            } else {
                System.out.println("certReturnUrl 验证失败");
                // TODO
                return "failure";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "failure";
        }
    }

    /**
     * 要求外部订单号必须唯一。
     * @return {String}
     */
    private String getOutTradeNo() {
        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
        Date date = new Date();
        String key = format.format(date);
        key = key + System.currentTimeMillis();
        key = key.substring(0, 15);
        return key;
    }

}